﻿using IOP.Pulsar.Abstractions;
using IOP.Pulsar.Default;
using IOP.Pulsar.Server;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace IOP.Pulsar.Hosting
{
    /// <summary>
    /// 主机构建者
    /// </summary>
    public class PulsarHostBuilder : IPulsarHostBuilder
    {
        /// <summary>
        /// 服务集合
        /// </summary>
        private IServiceCollection _services;
        /// <summary>
        /// 主机构建者上下文
        /// </summary>
        private HostBuilderContext _hostBuilderContext;
        /// <summary>
        /// 服务提供者
        /// </summary>
        private IServiceProvider _servicesProvider;
        /// <summary>
        /// 启动项集合
        /// </summary>
        private IEnumerable<IStartup> _startups;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="services">服务集合</param>
        /// <param name="builderContext">主机构建者上下文</param>
        public PulsarHostBuilder(IServiceCollection services, HostBuilderContext builderContext)
        {
            _services = services ?? throw new ArgumentNullException(nameof(services));
            _hostBuilderContext = builderContext ?? throw new ArgumentNullException(nameof(builderContext));
        }

        /// <summary>
        /// 构建
        /// </summary>
        public void Build()
        {
            _servicesProvider = _services.BuildServiceProvider();
            RunStartup();
        }

        /// <summary>
        /// 配置服务
        /// </summary>
        /// <param name="configureServices"></param>
        /// <returns></returns>
        public IPulsarHostBuilder ConfigureServices(Action<IServiceCollection> configureServices)
        {
            if (configureServices == null) throw new ArgumentNullException(nameof(configureServices));
            configureServices(_services);
            return this;
        }
        /// <summary>
        /// 配置服务
        /// </summary>
        /// <param name="configureServices"></param>
        /// <returns></returns>
        public IPulsarHostBuilder ConfigureServices(Action<HostBuilderContext, IServiceCollection> configureServices)
        {
            if (configureServices == null) throw new ArgumentNullException(nameof(configureServices));
            configureServices(_hostBuilderContext, _services);
            return this;
        }

        /// <summary>
        /// 配置服务器
        /// </summary>
        /// <param name="builder"></param>
        /// <returns></returns>
        public IPulsarHostBuilder Configure(Action<IServerBuilder, IHostEnvironment> builder)
        {
            if (builder == null) throw new ArgumentNullException(nameof(builder));
            var startup = new DelegateStartup(builder);
            _services.AddSingleton<IStartup>((factory) => startup);
            _services.AddSingleton<IServerBuilder, ServerBuilder>();
            return this;
        }

        /// <summary>
        /// 执行Startup文件方法
        /// </summary>
        private void RunStartup()
        {
            EnsureStartup();
            foreach (var item in _startups)
                item.ConfigureServices(_services);
        }

        /// <summary>
        /// 确认是否存在Startup文件
        /// </summary>
        private void EnsureStartup()
        {
            if (_startups != null) return;
            _startups = _servicesProvider.GetServices<IStartup>();
            if (!_startups.Any())
                throw new InvalidOperationException($"No application configured. Please specify startup via IHostBuilder.UseStartup, IHostBuilder.Configure, injecting {nameof(IStartup)} or specifying the startup assembly via Startup in the server host configuration.");
        }
    }
}
